﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint;
using Microsoft.Office.Server.ActivityFeed;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.SharePoint.Utilities;
using System.Globalization;
using System.ServiceModel.Syndication;
using Microsoft.SharePoint.WebControls;
using System.Web;
using eGov.SharePoint.MyPeeps.WebParts;
using System.Security.Principal;
using System.Reflection;
using System.Net;
using eGov.SharePoint.MyPeeps.Properties;

namespace eGov.SharePoint.MyPeeps
{
    public class ActivityFeedEntity
    {
        public string EventDate { get; set; }
        public DateTime PublishedDate { get; set; }
        public string Message { get; set; }
        public string PublisherProfileLink { get; set; }
        public string PublisherPicture { get; set; }
        public string FeedIcon { get; set; }
        public string PublisherName { get; set; }
        public string Title { get; set; }
    }

    public class UserProfileUtility
    {
        protected Dictionary<long, ActivityType> CachedActivityTypesConsolidated = new Dictionary<long, ActivityType>();
        protected List<long> CachedCustomActivityTypeIds = null;

        protected Dictionary<long, ActivityType> CachedActivityTypesPublished = new Dictionary<long, ActivityType>();


        protected List<string> VerifiedUrls = null;
        protected List<string> InvalidUrls = null;

        public List<ActivityFeedEntity> GetActivityFeedsForMe(FeedSource FeedsSource, int FeedsLimit, out bool HasMoreFeeds)
        {
            HasMoreFeeds = false;
            List<ActivityFeedEntity> resultList = new List<ActivityFeedEntity>();
            Dictionary<string, string> cachePublisherPictureUris = new Dictionary<string, string>();
            this.VerifiedUrls = new List<string>();
            this.InvalidUrls = new List<string>();

            this.CachedCustomActivityTypeIds = new List<long>();

            SPServiceContext context = SPServiceContext.GetContext(SPContext.Current.Site);

            using (SPMonitoredScope GetListsBtnScope = new SPMonitoredScope("GetActivityFeedsForMe"))
            {
                UserProfileManager userProfileManager = new UserProfileManager(context);
                UserProfile myUserProfile = userProfileManager.GetUserProfile(false);

                ActivityManager activityManager = new ActivityManager(myUserProfile, context);

                ActivityEventsCollection myActivityEvents = null;
                switch (FeedsSource)
                {
                    case FeedSource.Published: myActivityEvents = activityManager.GetActivitiesByMe(Privacy.NotSet, FeedsLimit); break;
                    case FeedSource.Consolidated: myActivityEvents = activityManager.GetActivitiesForMe(FeedsLimit * 2); break;
                }

                List<long> activityTypes = new List<long>();
                foreach (var activityEvent in myActivityEvents)
                    if (activityTypes.Contains(activityEvent.ActivityTypeId) == false)
                        activityTypes.Add(activityEvent.ActivityTypeId);
                this.CacheActivityAPI(activityTypes, SPContext.Current.Site.ID, FeedsSource);

                Dictionary<SyndicationItem, ActivityEvent> feedItems = new Dictionary<SyndicationItem, ActivityEvent>();
                foreach (ActivityEvent actEvent in myActivityEvents)
                {
                    try
                    {
                        /// Force object actEvent to populate with data
                        System.Reflection.PropertyInfo propTemplateVariable = typeof(ActivityEvent).GetProperty("ATV", BindingFlags.Instance | BindingFlags.NonPublic);
                        ActivityTemplateVariable templateVariable = propTemplateVariable.GetValue(actEvent, null) as ActivityTemplateVariable;

                        /// Verify feed for referencing existing content
                        if (this.VerifyLinkedContent(actEvent) == false) continue;

                        ActivityType actType;
                        if (FeedSource.Consolidated == FeedsSource)
                            actType = this.CachedActivityTypesConsolidated[actEvent.ActivityTypeId];
                        else
                            actType = this.CachedActivityTypesPublished[actEvent.ActivityTypeId];

                        ActivityTemplate template = actType.ActivityTemplates[ActivityTemplatesCollection.CreateKey(actEvent.IsRolledUp)];

                        if (this.CachedCustomActivityTypeIds.Contains(actEvent.ActivityTypeId))
                        {
                            // temp if clause
                            FieldInfo fieldTitleFormatLocStringName = typeof(ActivityTemplate).GetField("m_TitleFormatLocStringName", BindingFlags.Instance | BindingFlags.NonPublic);
                            fieldTitleFormatLocStringName.SetValue(template, actEvent.Name);
                        }

                        feedItems.Add(actEvent.CreateSyndicationItem(actType, template, ContentType.Html), actEvent);
                        if (feedItems.Count == FeedsLimit)
                        {
                            HasMoreFeeds = true; break;
                        }
                    }
                    catch { }
                }

                foreach (var feedItem in feedItems)
                {
                    try
                    {
                        ActivityFeedEntity newEntity = new ActivityFeedEntity();

                        newEntity.EventDate = FormatPublishedDateTime(feedItem.Key.PublishDate.LocalDateTime.Add(feedItem.Key.PublishDate.Offset));
                        newEntity.PublishedDate = feedItem.Key.PublishDate.LocalDateTime.Add(feedItem.Key.PublishDate.Offset);

                        this.FormatFeedIcon(feedItem.Value, newEntity);

                        if (feedItem.Key.Authors != null && feedItem.Key.Authors.Count > 0)
                        {
                            newEntity.PublisherName = feedItem.Key.Authors[0].Name;
                            if (cachePublisherPictureUris.ContainsKey(newEntity.PublisherName))
                                // Profile picture cached
                                newEntity.PublisherPicture = cachePublisherPictureUris[newEntity.PublisherName];
                            else
                            {
                                string accountname = string.Empty;
                                if (feedItem.Key.Authors[0].Name.IndexOf("\\") > -1)
                                    accountname = feedItem.Key.Authors[0].Name;
                                else
                                {
                                    string[] values = feedItem.Key.Authors[0].Uri.ToString().ToLower().Split(new string[] { "accountname=" }, StringSplitOptions.None);
                                    if(values.Length > 1)
                                    accountname = values[1];
                                    accountname = accountname.Replace("%5c", "\\");
                                }

                                // Evaluate profile picture
                                newEntity.PublisherPicture = this.GetUserProfileImage(userProfileManager, accountname);

                                // Cache profile picture link
                                cachePublisherPictureUris.Add(newEntity.PublisherName, newEntity.PublisherPicture);
                            }
                            if (String.IsNullOrEmpty(feedItem.Key.Authors[0].Uri) == false)
                                newEntity.PublisherProfileLink = feedItem.Key.Authors[0].Uri;
                        }

                        if (feedItem.Key.Content is TextSyndicationContent)
                        {
                            string content = (feedItem.Key.Content as TextSyndicationContent).Text;
                            int TitleEnd = content.IndexOf("<br/>");
                            if (TitleEnd > 0)
                            {
                                newEntity.Title = content.Substring(0, TitleEnd);
                                newEntity.Message = content.Substring(TitleEnd + 5).Replace("<br/>", "<div class='GenericFeed_EventsSpacer'></div>");
                            }
                            else newEntity.Title = content;

                            if (feedItem.Value != null && feedItem.Value.Name != null)
                                if (feedItem.Value.Name.ToLower() == "status message")
                                    newEntity.Title = newEntity.Title.Replace("says", "updated internal status: ");

                            if (FeedsSource == FeedSource.Published)
                            {
                                if (newEntity.Message != null)
                                    newEntity.Message = newEntity.Message.Replace("tempClass", "GenericFeed_FeedPicture");
                            }
                        }

                        resultList.Add(newEntity);
                    }
                    catch (Exception ex)
                    {

                    }
                }
            }
            return resultList;
        }

        protected void FormatFeedIcon(ActivityEvent feedData, ActivityFeedEntity newEntity)
        {
            switch (feedData.ActivityTypeId)
            {
                case 2: goto case 11;
                case 4: goto case 11;
                case 37: newEntity.FeedIcon = Properties.Settings.Default.FeedIcon_facebook; break;
                case 36: newEntity.FeedIcon = Properties.Settings.Default.FeedIcon_twitter; break;
                case 6: newEntity.FeedIcon = Properties.Settings.Default.FeedIcon_newcolleague; break;
                case 9: newEntity.FeedIcon = Properties.Settings.Default.FeedIcon_blogpost; break;
                case 11: newEntity.FeedIcon = Properties.Settings.Default.FeedIcon_membership; ; break;
                default: newEntity.FeedIcon = Properties.Settings.Default.FeedIcon_generic; break;
            }
        }

        /// <summary>
        /// Due to security measures, using AcctivityApplication and ActivityTypes are limited to administrators of User Profile service
        /// </summary>
        protected void CacheActivityAPI(List<long> ActivityTypes, Guid siteID, FeedSource FeedsSource)
        {

            Guid SPSiteGuid = siteID;

            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
                using (SPSite Site = new SPSite(SPSiteGuid))
                {
                    HttpContext currentContext = HttpContext.Current;
                    try
                    {
                        HttpContext.Current = null;
                        SPServiceContext spContext = SPServiceContext.GetContext(Site);

                        UserProfileManager userManager = new UserProfileManager(spContext);
                        string accPoolProfileName = WindowsIdentity.GetCurrent().Name;
                        UserProfile accPoolProfile = null;
                        if (userManager.UserExists(accPoolProfileName)) accPoolProfile = userManager.GetUserProfile(accPoolProfileName);
                        else userManager.CreateUserProfile(accPoolProfileName);

                        ActivityManager activityManager = new ActivityManager(accPoolProfile, spContext);
                        foreach (long activityTypeId in ActivityTypes)
                        {
                            foreach (var activityApplication in activityManager.ActivityApplications)
                            {
                                if (activityApplication.ActivityTypes[activityTypeId] != null)
                                {
                                    if (FeedSource.Consolidated == FeedsSource)
                                        this.CachedActivityTypesConsolidated.Add(activityTypeId, activityApplication.ActivityTypes[activityTypeId]);
                                    else
                                        this.CachedActivityTypesPublished.Add(activityTypeId, activityApplication.ActivityTypes[activityTypeId]);
                                }
                            }
                        }

                        ActivityApplication actApplication = activityManager.ActivityApplications[Settings.Default.ActivityApplicationTitle_eGovCustomFeeds];
                        foreach (ActivityType actType in actApplication.ActivityTypes)
                            this.CachedCustomActivityTypeIds.Add(actType.ActivityTypeId);
                    }
                    catch (UnauthorizedAccessException securityEx)
                    { }
                    catch (SPException sharepointEx)
                    { }
                    finally
                    {
                        HttpContext.Current = currentContext;
                    }
                }
            });
        }

        protected bool VerifyLinkedContent(ActivityEvent Feed)
        {
            return true;
            if (Feed == null) return false;
            if (Feed.Link != null)
                if (this.IsUrlAvailable(Feed.Link.Href) == false)
                    return false;
            if (Feed.Link2 != null)
                if (this.IsUrlAvailable(Feed.Link2.Href) == false)
                    return false;
            if (Feed.ActivityTypeId == 40 && Feed.Value != null)
                if (this.IsUrlAvailable(Feed.Value) == false)
                    return false;
            if (Feed.LinksList != null)
                foreach (var aLink in Feed.LinksList)
                    if (this.IsUrlAvailable(aLink.Href) == false)
                        return false;
            return true;
        }

        protected bool IsUrlAvailable(string url)
        {
            if (String.IsNullOrEmpty(url)) return true;
            if (this.VerifiedUrls.Contains(url)) return true;
            if (this.InvalidUrls.Contains(url)) return false;

            try
            {
                HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
                req.Credentials = CredentialCache.DefaultNetworkCredentials;
                req.Method = "HEAD";
                req.Timeout = 250;
                using (HttpWebResponse rsp = (HttpWebResponse)req.GetResponse())
                {
                    if (rsp.StatusCode == HttpStatusCode.OK)
                    {
                        VerifiedUrls.Add(url);
                        return true;
                    }
                    else this.InvalidUrls.Add(url);
                }

            }
            catch (WebException)
            {
                this.InvalidUrls.Add(url);
            }

            // Otherwise
            return false;
        }

        protected static string FormatPublishedDateTime(DateTime date)
        {
            string timePosted = string.Empty;
            TimeSpan ts = DateTime.Now.Subtract(date);

            if (date > DateTime.Now)
            {
                /// Incorrectly evaluated published date
                return String.Format("recently");
            }

            timePosted = string.Format("Posted {0} days, {1} hours, {2} minutes ago", ts.Days, ts.Hours, ts.Minutes);
            if (ts.Days <= 0 && ts.Hours <= 0 && ts.Minutes <= 0 && ts.Seconds <= 60)
                timePosted = string.Format("Posted {0} seconds ago", ts.Seconds);
            if (ts.Days <= 0 && ts.Hours <= 0 && ts.Minutes <= 60 && ts.Minutes > 0)
                timePosted = string.Format("Posted {0} minutes ago", ts.Minutes);
            if (ts.Days <= 0 && ts.Hours <= 24 && ts.Hours > 0)
                timePosted = string.Format("Posted {0} hours, {1} minutes ago", ts.Hours, ts.Minutes);
            if (ts.Days > 0)
                timePosted = string.Format("Posted {0} days, {1} hours, {2} minutes ago", ts.Days, ts.Hours, ts.Minutes);

            return timePosted;
        }

        protected string GetUserProfileImage(UserProfileManager userProfileManager, string AccountName)
        {
            string userImg = string.Empty;

            try
            {
                UserProfile uProfile = null;
                if (userProfileManager.UserExists(AccountName)) uProfile = userProfileManager.GetUserProfile(AccountName);




                if (uProfile != null && !String.IsNullOrEmpty(uProfile["PictureURL"].Value as string))
                    return uProfile["PictureURL"].Value.ToString();
            }
            catch { }

            return SPContext.Current.Web.Url + "/_layouts/images/O14_person_placeHolder_96.png";
        }
    }
}
